package edu.hda.pt.server.connections;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import edu.hda.pt.server.PTServer;
import edu.hda.pt.server.connections.mina.ServerProtocolHandler;
import edu.hda.pt.server.connections.mina.StreamThread;
import edu.hda.pt.utils.Stream;
import edu.hda.pt.utils.Stream.StreamState;
import edu.hda.pt.utils.connections.mina.MinaConstants;
import edu.hda.pt.utils.connections.mina.codec.CodecFactory;

/**
 * Server implementation for the connection method Apache MINA
 * 
 * @author Marc Hammerton
 * 
 */
public class PTServerMINA extends PTServer {

	private SocketAcceptor acceptor;
	private StreamThread st;

	/**
	 * @see edu.hda.pt.server.PTServer#start()
	 */
	@Override
	public void start() {
		acceptor = new NioSocketAcceptor();
		acceptor.getSessionConfig().setTcpNoDelay(true);
		acceptor.getSessionConfig().setReadBufferSize(16384 * 10);
		acceptor.getFilterChain().addLast("protocol",
				new ProtocolCodecFilter(new CodecFactory()));

		// acceptor.getFilterChain().addLast("logger", new LoggingFilter() );

		// bind
		acceptor.setHandler(new ServerProtocolHandler(this));
		try {
			acceptor.bind(new InetSocketAddress(MinaConstants.PORT));
		} catch (IOException e) {
			e.printStackTrace();
		}

		st = new StreamThread();
		st.start();

	}

	/**
	 * @see edu.hda.pt.server.PTServer#stop()
	 */
	@Override
	public void stop() {
	}

	/**
	 * Method for handling stream requests. If a new stream request is received,
	 * it is added to the
	 * {@link edu.hda.pt.server.connections.mina.StreamThread}, which then
	 * starts sending frames to the client. When a client requests the stream to
	 * be stopped, the client is removed from the
	 * {@link edu.hda.pt.server.connections.mina.StreamThread}.
	 * 
	 * @param stream
	 *            - The stream object with information about the request
	 * @param session
	 *            - The session with information about the client connection
	 */
	public void handleStream(Stream stream, IoSession session) {
		if (stream.getState() == StreamState.START) {
			// Init StreamThread
			if (st.getFileSize() == 0) {
				synchronized (st) {
					st.setFileSize(stream.getFs());
					st.addSession(session);
					st.notify();
				}

			} else if (stream.getFs() == st.getFileSize()) {
				synchronized (st) {
					st.addSession(session);
				}
			}
			stream.setState(StreamState.RUNNING);

		} else if (stream.getState() == StreamState.FINISH) {
			st.removeSession(session);
			stream.setState(StreamState.STOPPED);
		}

	}

}
